package com.wayne.security.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.wayne.security.handler.MyAuthenticationSuccessHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 开启权限配置
        http.authorizeRequests()
                // 所有的请求都要认证之后 才能访问
                .anyRequest().authenticated()
                .and()
                // 开启表单登录配置
                .formLogin()
                // 登录页面地址
                .loginPage("/mylogin.html")
                // 登录接口地址
                .loginProcessingUrl("/doLogin")
                // 登录成功后的跳转地址 (302 客户端重定向，由其他页面拦截，登录后会跳回拦截的页面[可以配置alwaysUse:true 强制跳转])
                .defaultSuccessUrl("/index.html", false)
                // 登录成功后的跳转地址 (服务端重定向  强制重定向至配置的页面)
                // .successForwardUrl("/index.html")
                // .successHandler(successHandler())
                .successHandler(new MyAuthenticationSuccessHandler())
                // 登录失败后的跳转地址 (302 客户端重定向)
                // .failureUrl("/mylogin.html")
                // 登录失败后的跳转地址 (服务端重定向)
                // .failureForwardUrl("/mylogin.html")
                .failureHandler(failureHandler())
                // 登录用户名的参数名称
                .usernameParameter("uname")
                // 登录密码的参数名称
                .passwordParameter("passwd")
                // 登录相关的页面和接口不做拦截
                .permitAll()
                .and()
                // 开启登出配置
                .logout()
                // 注销登录请求地址，默认是 GET 请求
                //.logoutUrl("/logout")
                // 指定登出方式
                .logoutRequestMatcher(new OrRequestMatcher(
                        new AntPathRequestMatcher("/logout1", HttpMethod.GET.name()),
                        new AntPathRequestMatcher("/logout2", HttpMethod.POST.name())
                ))
                // 是否使 session 失效，默认为 true
                .invalidateHttpSession(true)
                // 是否清除认证信息，默认为 true
                .clearAuthentication(true)
                // 定制根据登出方式设置返回
                .defaultLogoutSuccessHandlerFor((req, resp, auth) -> {
                         resp.setContentType("application/json;charset=utf-8");
                         Map<String, Object> result = new HashMap<>();
                         result.put("status", 200);
                         result.put("msg", "通过logout1注销成功!");
                         ObjectMapper om = new ObjectMapper();
                         String s = om.writeValueAsString(result);
                         resp.getWriter().write(s);
                }, new AntPathRequestMatcher("/logout1",HttpMethod.GET.name()))
                .defaultLogoutSuccessHandlerFor((req, resp, auth) -> {
                    resp.setContentType("application/json;charset=utf-8");
                    Map<String, Object> result = new HashMap<>();
                    result.put("status", 200);
                    result.put("msg", "通过logout2注销成功!");
                    ObjectMapper om = new ObjectMapper();
                    String s = om.writeValueAsString(result);
                    resp.getWriter().write(s);
                }, new AntPathRequestMatcher("/logout2",HttpMethod.POST.name()))
                // 登出后自定义处理
                // .logoutSuccessHandler(((req, resp, auth) -> {
                //     resp.setContentType("application/json;charset=utf-8");
                //     Map<String, Object> result = new HashMap<>();
                //     result.put("status", 200);
                //     result.put("msg", "注销成功!");
                //     ObjectMapper om = new ObjectMapper();
                //     String s = om.writeValueAsString(result);
                //     resp.getWriter().write(s);
                // }))
                // 登出成功后重定向地址
                //.logoutSuccessUrl("/mylogin.html")
                .and()
                // 禁用 CSRF 防御功能
                .csrf().disable();
    }

    SavedRequestAwareAuthenticationSuccessHandler successHandler() {
        SavedRequestAwareAuthenticationSuccessHandler handler =
                new SavedRequestAwareAuthenticationSuccessHandler();
        handler.setDefaultTargetUrl("/index");
        handler.setTargetUrlParameter("target");
        return handler;
    }

    SimpleUrlAuthenticationFailureHandler failureHandler() {
        SimpleUrlAuthenticationFailureHandler handler =
                new SimpleUrlAuthenticationFailureHandler("/mylogin.html");
        handler.setUseForward(true);
        return handler;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("javaboy").password("{noop}123").roles("admin").build());
        manager.createUser(User.withUsername("sang").password("{noop}123").roles("user").build());
        auth.userDetailsService(manager);
    }
}
